//: Playground - noun: a place where people can play

import UIKit

//: # swfit 读书笔记

//: ## 协议

//: ### 协议语法
protocol someprotocol{
    //: 实现协议的方法
}

//: 遵守协议
struct someStruct:someprotocol{
    
}

//: ### 属性要求
//: 协议总是用 var 关键字来声明变量属性，
//: { set get } 和 { get } 其实没什么卵用， 他们代表的是 可读写 和 可读 ，但是 { get } 也是可写的
//: 唯一的区别是 { set get } 不能是常量属性或只读的计算型属性
protocol someProtocolTwo{
    //: 可读写
    var mustBeSettable:Int{set get}
    //: 可读、计算型
    var doesNotNeedToBeSettable:Int{get}
}

//:在协议中定义类型属性时，总是使用 static 关键字作为前缀。当类类型遵循协议时，除了 static 关键字，还可以使用 class 关键字来声明类型属性
protocol anotherProtocol{
    static var someTypeProperty:Int {get set}
}

//: ### 方法要求
// : 可以在协议中定义具有可变参数的方法，和普通方法的定义方式相同。但是，不支持为协议中的方法的参数提供默认值。

protocol someProtocolThree{
    static func someTypeMethod()
}

protocol randomNumberGenerate{
    func randomNum() -> Double
}

class randomClass:randomNumberGenerate{
    var lastNum = 42.0
    //: 随便实现一下方法
    func randomNum() -> Double {
        return lastNum * 1 * 2/5
    }
}

//: ### Mutating 方法要求(结构体和枚举适用)
//: 实现协议中的 mutating 方法时，若是类类型，则不用写 mutating 关键字。而对于结构体和枚举，则必须写 mutating 关键字。
protocol Togglable{
    mutating func toggle()
}
enum SwitchOnOff:Togglable{
    case Off,On
    mutating func toggle() {
        switch self {
        case .On:
            self = .Off
        default:
            self = .On
        }
    }
}

var lightSwitch = SwitchOnOff.Off
lightSwitch.toggle()
print("\(lightSwitch)")

//: ### 析构器要求
protocol initProtocol{
    init(name:String)
}

//: 实现的时候必须写上 required
class InitClass:initProtocol{
    required init(name: String) {
        
    }
}

//: 如果类已经被标记为 final，那么不需要在协议构造器的实现中使用 required 修饰符，因为 final 类不能有子类。关于 final 修饰符的更多内容，请参见防止重写。
final class InitTwoClass:initProtocol{
    init(name: String) {
        
    }
}

//: 如果一个子类重写了父类的指定构造器，并且该构造器满足了某个协议的要求，那么该构造器的实现需要同时标注 required 和 override 修饰符：

class InitThreeClass{
    init() {
        
    }
}

protocol InitThreeProtocol{
    init()
}

class InitFourClass:InitThreeClass,InitThreeProtocol{
    required override init() {
        //: 因为遵循协议，需要加上 required
        //: 因为继承自父类，需要加上 override
        super.init()
    }
}

//: ### 协议作为类型
//: 作为函数、方法或构造器中的参数类型或返回值类型
//: 作为常量、变量或属性的类型
//: 作为数组、字典或其他容器中的元素类型
class Dice {
    let sides:Int
    let generator:randomNumberGenerate
    
    init(sides:Int,generator:randomNumberGenerate) {
        self.sides = sides;
        self.generator = generator;
    }
    
    func roll() -> Int{
        //: generator 是遵循了 randomNumberGenerate 协议并实现了randomNum方法的  类
        return Int(generator.randomNum() * Double(sides)) + 1
    }
}

var d6 = Dice(sides: 6, generator: randomClass())
for _ in 1...5 {
    print("Random dice roll is \(d6.roll())")
}
    

//: ### 代理模式(委托)(就是回调)

protocol protocolBackAction{
    func comeBack()
}

class protocolFourClass:protocolBackAction{
    init() {
        print("1")
        let threeClass = protocolThreeClass()
        threeClass.protocolPro = self
        threeClass.staterComeBack()
    }
    
    func comeBack() {
        print("3")
        print("我是回调")
    }
    
}

class protocolThreeClass{
    var protocolPro:protocolBackAction?
    init() {
    }
    
    func staterComeBack() {
        print("2")
        //: 通过外部模拟 回调触发方法
        protocolPro?.comeBack()
    }
    
}

protocolFourClass()

//: ### 通过扩展添加协议一致性(就是通过  extension  帮着 实现一些协议)
protocol TextRepresentable {
    var textualDescription: String { get }
}

extension Dice: TextRepresentable {
    var textualDescription: String {
        return "A \(sides)-sided dice"
    }
}

let d12 = Dice(sides: 12, generator: randomClass())
print(d12.textualDescription)

//: ### 通过扩展遵循协议

struct Hamster {
    var name: String
    //: 实现协议写在主体里
    var textualDescription: String {
        return "A hamster named \(name)"
    }
}
//: 遵循协议写在 扩展里
extension Hamster: TextRepresentable {}

//: ### 协议类型集合
let ham = Hamster (name: "sdaf")

let things:[TextRepresentable] = [d12,ham]

//: ### 协议的继承
//: 协议的多继承是通过逗号隔开的
protocol inheringProtcol:someprotocol,anotherProtocol{
    //: 这里写这个协议自己的 方法 属性等
}

protocol PrettyTextRepresentable:TextRepresentable{
    var PrettyTextualDescription: String { get }
}

class someProClass:PrettyTextRepresentable{
    var PrettyTextualDescription: String{
        return "PrettyTextualDescription"
    }
    
    var textualDescription: String{
        return "textualDescription"
    }
    
    func NSlog() {
        print("\(PrettyTextualDescription) - \(textualDescription)")
    }
    
}
someProClass().NSlog()

//: ### 类类型专属协议
//: 就是在 协议后面 写上 :class 枚举和结构体就不能遵守了
protocol classTypeProtocol:class,anotherProtocol{
    
}

//: ### 协议合成
//: 主要针对的是参遵守多个协议， 继承多个协议用 , 隔开就行
protocol nameProtocol {
    var name: String { get }
}

protocol ageProtocol {
    var age: String { get }
}

struct Person:nameProtocol,ageProtocol{
    var name: String
    var age: String
}

func wishHappyBirthday(to celebrator:nameProtocol&ageProtocol){
    print("\(celebrator.name) 的年龄是 \(celebrator.age)")
}

let birthdayPerson = Person (name: "赵日天", age: "18")

wishHappyBirthday(to: birthdayPerson)

//: ### 检查协议的一致性
//:is 用来检查实例是否符合某个协议，若符合则返回 true，否则返回 false。
//:as? 返回一个可选值，当实例符合某个协议时，返回类型为协议类型的可选值，否则返回 nil。
//:as! 将实例强制向下转换到某个协议类型，如果强转失败，会引发运行时错误。”
//:as
protocol HasArea{
    var area: Double { get }
}

class country:HasArea{
    var area: Double
    init(area:Double) {
        self.area = area
    }
}


class Circle:HasArea{
    let pi = 3.1415926
    var radius:Double
    var area: Double{return pi * radius * radius}
    init(radius:Double) {
        self.radius = radius
    }
}

class Animal{
    let leg:Int
    init(leg:Int) {
        self.leg = leg
    }
    func diffIdentifier() -> NSObjectProtocol {
        return leg as NSObjectProtocol
    }
}

let objects:[AnyObject] = [Circle (radius: 2.0),country (area: 110.0),Animal (leg: 4)]

for object in objects {
    if let objectWithArea = object as? HasArea {
        print("as? - \(objectWithArea) 遵守了 HasArea 协议")
    }else{
        print("as? - \(object) 没遵守 HasArea 协议")
    }
    
    
    if object is HasArea {
        print("is - \(object) 遵守了 HasArea 协议")
    }else{
        print("is - \(object) 没遵守 HasArea 协议")
    }
}

//: ### 可选的协议要求
//: 枚举和结构体是不能遵循这个协议的
@objc protocol optionalProtocol{
    @objc optional func showMyName(name:String)
    func sayHello()
}

//: class 前没加  @objc  也是可以的
class optionalClass:optionalProtocol{
    func sayHello() {
        print("hello")
    }
    
    func showMyName(name: String) {
        print("我的姓名\(name)")
    }
    func saySB() {
        print("山炮")
    }
    
}

//: ### 协议扩展
//: 是给协议通过 extension 扩展方法
extension optionalProtocol {  func saySB() {}  }
optionalClass().saySB()

//: ### 为协议扩展添加限制条件
extension Collection where Iterator.Element: TextRepresentable {
    var textualDescription: String {
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}

let murrayTheHamster = Hamster(name: "Murray")
let morganTheHamster = Hamster(name: "Morgan")
let mauriceTheHamster = Hamster(name: "Maurice")
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]

print(hamsters.textualDescription)
